home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / mint / bed02 / bed.c < prev    next >
C/C++ Source or Header  |  1993-08-15  |  49KB  |  1,757 lines

  1. /*     BED   -    Bermuda EDitor     */
  2. /*     (c) Vincent Pomey -   1993    */
  3. /*   free to use - do not complain   */
  4.  
  5. /* $Id: bed.c,v 1.3 1993/08/15 20:53:32 vincent Exp $ */
  6. /* v 0.0  oct 92  start                */
  7. /* v 0.1  feb 93  first release        */
  8. /* v 0.2  apr 93  fixes(quote...)   */
  9. /* $Log: bed.c,v $
  10.  * Revision 1.3  1993/08/15  20:53:32  vincent
  11.  * plein de petits bugs
  12.  *
  13.  * Revision 1.2  1993/06/15  17:19:56  vincent
  14.  * Print message
  15.  * */
  16.  
  17. #include <stdio.h>
  18. #include <time.h>
  19. #include <stdlib.h>
  20.  
  21. #include <Xm/RowColumn.h>
  22. #include <Xm/MainW.h>
  23. #include <Xm/CascadeB.h>
  24. #include <Xm/CascadeBG.h>
  25. #include <Xm/PushB.h>
  26. #include <Xm/PushBG.h>
  27. #include <Xm/LabelG.h>
  28. #include <Xm/SeparatoG.h>
  29. #include <Xm/Text.h>
  30. #include <Xm/TextF.h>
  31. #include <Xm/SelectioB.h>
  32. #include <Xm/MessageB.h>
  33. #include <Xm/FileSB.h>
  34. #include <Xm/ToggleBG.h>
  35. #include <Xm/Frame.h>
  36. #include <X11/StringDefs.h>
  37.  
  38. #include "bed.h"
  39. #include "missing.h"
  40. #include "bed.xbm"
  41.  
  42. Widget            RowCol, TextWidget, AreaWidget, FromWidget, ToWidget, DateWidget, SubjWidget;
  43. XtAppContext    App;
  44.  
  45. int        ourzone, ournet, ournode, ourpoint;
  46. char    sysop[80];
  47. int        curr_area=-1, num_msgs, curr_msg;
  48. FILE    *texts=NULL;
  49. struct    Hdr *headers;
  50. int        num_areas;            /* number of areas */
  51. char    *edit_cmd;
  52. char    temp1[50], temp2[50];
  53.  
  54. #define Str(a,b) XtVaTypedArg, a, XmRString, b, strlen(b)+1
  55.  
  56. int        echozone, echonet, echonode, echopoint;        /* original of the current echomail message */
  57. char    replyid[25];        /* msgid of the current message */
  58.  
  59. static XtResource ressources[] = {{
  60.     "editor",
  61.     "Editor",
  62.     XtRString, sizeof(String),
  63.     0,
  64.     XtRString, "xterm -e vi"
  65.     },
  66.     };
  67.  
  68. void ParseAdr (char *dest, int *zone, int *net, int *node, int *point)
  69. {
  70.     char *nodea;
  71.     int i;
  72.     
  73.     *zone=ourzone;
  74.     *net=ournet;
  75.     *node=ournode;
  76.     *point=0;
  77.     
  78.     nodea=rindex(dest, '@');
  79.     if (!nodea)
  80.         nodea=rindex(dest, '(');
  81.  
  82.     if (nodea) {
  83.         if (rindex(nodea+1, ':'))
  84.             sscanf (nodea+1, "%d:%d/%d.%d", zone, net, node, point);
  85.         else
  86.             sscanf (nodea+1, "%d/%d.%d", net, node, point);
  87.  
  88.         if (nodea[-1]==' ') nodea[-1]=0;        /* bidouille pour eviter un espace a la fin du nom */
  89.             else nodea[0]=0;
  90.     }
  91.     else {
  92.         /* no address -> scan user list */
  93.         FILE *users;
  94.         char ligne[100], *p, *q;
  95.  
  96.         p=getenv ("MAILER");
  97.         if (p)
  98.             sprintf (ligne, "%s/ulist.txt", p);
  99.         else
  100.             strcpy (ligne, "ulist.txt");
  101.         users=fopen (ligne, "r");
  102.  
  103.         if (users != NULL) {
  104.             /* mets les majuscules */
  105.             if (strlen (dest)==2)
  106.                 strupr (dest);
  107.             else {
  108.                 *dest = toupper (*dest);
  109.                 if (p=rindex (dest, ' ')) {
  110.                     p++;
  111.                     *p=toupper (*p);
  112.                 }
  113.             }
  114.             
  115.             while (!feof(users)) {
  116.               if (fgets (ligne, 100, users)) {
  117.                 /* split name/address */
  118.                 if (p=rindex(ligne, '\t'))
  119.                     *p=0;
  120.                 else
  121.                     break;        /* format non valide */
  122.                 /* check initials */
  123.                 if (strlen(dest)==2)
  124.                     if ((ligne[0]==*dest) && (q=rindex(ligne, ' ')) && (q[1] = dest[1]))
  125.                         strcpy (dest, ligne);
  126.                 if (!stricmp (dest, ligne)) {
  127.                     sscanf (p+1, "%d:%d/%d.%d", zone, net, node, point);
  128.                     /* break;  no break since we should check for the latest entry (add in ulist
  129.                     does not remove previous entry. hu hu hu it's ugly */
  130.                 }
  131.               }
  132.             }
  133.             fclose (users);
  134.         }
  135.     }
  136.     i=strlen(dest)-1;
  137.     while ((i != 0) && ((dest[i]==' ') || (dest[i]=='\t')))
  138.         i--;
  139.     if ((dest[i]==' ') || (dest[i]=='\t'))
  140.         dest[i]=0;
  141. }    
  142.  
  143. /*#define OK_ISO_LATIN1*/
  144. /* very limited conversion from PC character set to ISO Latin1 */
  145. char Pc2Iso (unsigned char t)
  146. {
  147. #ifdef OK_ISO_LATIN1
  148.       /* my Motif doesn't like that, dunno why */
  149.       if (t==133) t=224; /* a' */
  150.       if (t==130) t=233; /* e' */
  151.       if (t==138) t=232; /* e` */
  152.       if (t==145) t=231; /* c, */
  153.       if (t==151) t=249; /* u` */
  154. #else
  155.       if (t==133) t='a'; /* a' */
  156.       if (t==130) t='e'; /* e' */
  157.       if (t==138) t='e'; /* e` */
  158.       if (t==145) t='c'; /* c, */
  159.       if (t==151) t='u'; /* u` */
  160. #endif
  161.  
  162.       return t;
  163. }
  164.  
  165.  
  166. /* General Motif functions */
  167.  
  168. void Focus (Widget w)
  169. {
  170.     /* twice because of Motif bug */
  171.     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  172.     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  173. }
  174.  
  175. void MakePosVisible (Widget w, int item)
  176. {
  177.     int top, visible;
  178.  
  179.     XtVaGetValues(w, XmNtopItemPosition, &top,
  180.                      XmNvisibleItemCount, &visible, NULL);
  181.     if (item < top)
  182.         XmListSetPos(w, item);
  183.     else if (item >= top+visible)
  184.         XmListSetBottomPos(w, item);
  185. }
  186.  
  187. /* Menus */
  188.  
  189. typedef struct _menu_item {
  190.     char    *label;
  191.     WidgetClass *class;
  192.     char    mnemonic;
  193.     char    *accelerator;
  194.     char    *accel_text;
  195.     void    (*callback)();
  196.     XtPointer callback_data;
  197. } MenuItem;
  198.  
  199. Widget BuildMenu(Widget parent, char *title, char mnemonic, MenuItem *items)
  200. {
  201.     Widget Pulldown, cascade, widget;
  202.     int i;
  203.     XmString str;
  204.  
  205.     Pulldown = XmCreatePulldownMenu(parent, "_pulldown", NULL, 0);
  206.     str = XmStringCreateSimple(title);
  207.     cascade = XtVaCreateManagedWidget(title,
  208.         xmCascadeButtonWidgetClass, parent,
  209.         XmNsubMenuId, Pulldown,
  210.         XmNlabelString, str,
  211.         XmNmnemonic, mnemonic, NULL);
  212.     XmStringFree(str);
  213.  
  214.     for (i=0; items[i].label != NULL; i++) {
  215.         widget = XtVaCreateManagedWidget(items[i].label, *items[i].class, Pulldown, NULL);
  216.         if (items[i].mnemonic)
  217.             XtVaSetValues (widget, XmNmnemonic, items[i].mnemonic, NULL);
  218.         if (items[i].accelerator) {
  219.             str = XmStringCreateSimple (items[i].accel_text);
  220.             XtVaSetValues (widget,
  221.                 XmNaccelerator, items[i].accelerator,
  222.                 XmNacceleratorText, str, NULL);
  223.             XmStringFree (str);
  224.         }
  225.         if (items[i].callback)
  226.             XtAddCallback (widget, XmNactivateCallback, items[i].callback, items[i].callback_data);
  227.     }
  228.     return cascade;
  229. }
  230.  
  231. /* Bed commands */
  232.  
  233. /* from a message of Burt Juda in the UFGATE echo */
  234. void mksoftcr (char *text) {
  235.    int c1 = 0;        /* counter since last CR */
  236.    int c2 = 0;       /* counter since last SPACE */
  237.    unsigned char *t, *s;
  238.  
  239.    for (t=text; *t; t++)
  240.    {
  241.       c1++;
  242.       c2++;
  243.  
  244.       *t = Pc2Iso (*t);
  245.  
  246.       if ((*t == '\n') || (*t == '\r'))
  247.          {
  248.          c1 = 0;/* reset counters */
  249.          c2 = 0;
  250.          continue;
  251.          }
  252.       else
  253.         {
  254.         if ((*t == ' ') || (*t == '\t'))
  255.            {
  256.            s = t;
  257.            c2 = 0;
  258.            continue;
  259.            }
  260.         else
  261.            {
  262.            if (c1 > 78)
  263.               {
  264.               *s = '\n';
  265.               c1 = c2;
  266.               continue;
  267.               }
  268.         }
  269.       }
  270.    }
  271. }
  272.  
  273. char *strip_re (char *l)
  274. {
  275.     while (!strnicmp (l, "Re: ", 4))
  276.         l+=4;
  277.     return l;
  278. }
  279.  
  280. void DisplayMsg(void)
  281. {
  282.     char *buffer, *scan, *endkludge, *msgid, str[100];
  283.     FILE *msg;
  284.     int forw_repl, back_repl, c;
  285.  
  286.     if (curr_msg==-1) {
  287.         /* clear all fields */
  288.         sprintf (str, "Area   %s  [0/0]", areas[curr_area].area_name);
  289.         XtVaSetValues (AreaWidget, Str (XmNlabelString, str), NULL);
  290.         XtVaSetValues (FromWidget, Str (XmNlabelString, ""), NULL);
  291.         XtVaSetValues (ToWidget, Str (XmNlabelString, ""), NULL);
  292.         XtVaSetValues (DateWidget, Str (XmNlabelString, ""), NULL);
  293.         XtVaSetValues (SubjWidget, Str (XmNlabelString, ""), NULL);
  294.         XmTextSetString (TextWidget, "");
  295.         msgid=NULL; replyid[0]=0;
  296.         return;
  297.         /* should shadow Reply/ReplyNetmail/Change/Delete/Save */
  298.     }
  299.         
  300.     /* if netmail, set recv flag */
  301.     if ((curr_area==0) && (!(RECEIVED & headers[curr_msg].flags)) && (!stricmp (headers[curr_msg].to, sysop))) {
  302.         headers[curr_msg].flags |= RECEIVED;
  303.         sprintf (str, "%s.HDR", areas[curr_area].area_file);
  304.         msg=fopen (str, "r+");
  305.         fseek (msg, curr_msg*sizeof (struct Hdr), SEEK_SET);
  306.         fwrite (&headers[curr_msg], sizeof (struct Hdr), 1, msg);
  307.         fclose (msg);
  308.     }
  309.     
  310.     buffer=XtMalloc(headers[curr_msg].size+1);
  311.     fseek (texts, headers[curr_msg].Mstart, SEEK_SET);
  312.     fread (buffer, 1, headers[curr_msg].size+1, texts);
  313.     buffer[headers[curr_msg].size]=0;
  314.  
  315.     msgid=NULL; replyid[0]=0;
  316.     endkludge=buffer;
  317.     while (*endkludge=='\01') {
  318.         if (!strncmp(endkludge, "\01MSGID:", 7))
  319.             msgid=endkludge+7;
  320.         endkludge=strchr(endkludge, '\n')+1;
  321.     }
  322.     if (msgid) {
  323.         *strchr(msgid, '\n')=0;
  324.         strncpy (replyid, msgid, 24);
  325.     }
  326.     
  327.     if (curr_area != 0) {
  328.         scan=strstr (endkludge, "\n * Origin:");
  329.         if (scan) {
  330.             scan=strchr (scan, '(');
  331.             echopoint=0;
  332.             sscanf (scan, "(%d:%d/%d.%d", &echozone, &echonet, &echonode, &echopoint);
  333.         }
  334.     } else {
  335.         echozone =headers[curr_msg].Ozone;
  336.         echonet  =headers[curr_msg].Onet;
  337.         echonode =headers[curr_msg].Onode;
  338.         echopoint=headers[curr_msg].Opoint;
  339.     }
  340.     
  341.     mksoftcr (endkludge);
  342.     XmTextSetString (TextWidget, endkludge);
  343.     XtFree (buffer);
  344.  
  345.     /* scan area for replies */
  346.     strcpy (str, strip_re(headers[curr_msg].topic));
  347.     c=curr_msg+1; forw_repl=0;
  348.     while ((c<num_msgs) &&
  349.           !((!(headers[c].flags & DELETED)) && !stricmp (str, strip_re(headers[c].topic))))
  350.         c++;
  351.     if (c<num_msgs)
  352.         forw_repl=1;
  353.         
  354.     c=curr_msg-1; back_repl=0;
  355.     while ((c>0) &&
  356.           !((!(headers[c].flags & DELETED)) && !stricmp (str, strip_re(headers[c].topic))))
  357.         c--;
  358.     if (c>0)
  359.         back_repl=1;
  360.  
  361.     
  362.     sprintf (str, "Area   %s  [%d/%d]        %s%s%s%s%s%s%s%s%s%s%s %s%s", areas[curr_area].area_name, curr_msg+1, num_msgs,
  363.                     (headers[curr_msg].flags&PRIVATE)  ? "Pvt ":"",
  364.                     (headers[curr_msg].flags&CRASH)    ? "Crash ":"",
  365.                     (headers[curr_msg].flags&RECEIVED) ? "Recv ":"",
  366.                     (headers[curr_msg].flags&SENT)     ? "Sent ":"",
  367.                     (headers[curr_msg].flags&FILEATCH) ? "W/File ":"",
  368.                     (headers[curr_msg].flags&MSGLOCAL) ? "Local ":"",
  369.                     (headers[curr_msg].flags&KILLSEND) ? "K/Sent ":"",
  370.                     (headers[curr_msg].flags&MSGHOLD)  ? "Hold ":"",
  371.                     (headers[curr_msg].flags&DIRECT)   ? "Direct ":"",
  372.                     (headers[curr_msg].flags&NOKILL)   ? "N/Kill ":"",
  373.                     (headers[curr_msg].flags&DELETED)  ? "Deleted ":"",
  374.                     back_repl ? "<-":"", forw_repl ? (back_repl?">":"->"):"");
  375.     XtVaSetValues (AreaWidget, Str (XmNlabelString, str), NULL);
  376.     if (curr_area==0)
  377.         sprintf (str, "From:  %s (%d:%d/%d.%d)", headers[curr_msg].from, headers[curr_msg].Ozone, headers[curr_msg].Onet, headers[curr_msg].Onode, headers[curr_msg].Opoint);
  378.     else sprintf (str, "From:  %s", headers[curr_msg].from);
  379.     XtVaSetValues (FromWidget, Str (XmNlabelString, str), NULL);
  380.     if (curr_area==0)
  381.         sprintf (str, "To:    %s (%d:%d/%d.%d)", headers[curr_msg].to, headers[curr_msg].Dzone, headers[curr_msg].Dnet, headers[curr_msg].Dnode, headers[curr_msg].Dpoint);
  382.     else sprintf (str, "To:    %s", headers[curr_msg].to);
  383.     XtVaSetValues (ToWidget, Str (XmNlabelString, str), NULL);
  384.     sprintf (str, "Date:  %s", headers[curr_msg].time);
  385.     XtVaSetValues (DateWidget, Str (XmNlabelString, str), NULL);
  386.     sprintf (str, "Subj:  %s", headers[curr_msg].topic);
  387.     XtVaSetValues (SubjWidget, Str (XmNlabelString, str), NULL);
  388. }
  389.  
  390. void NextMessage(void)
  391. {
  392.     curr_msg++;
  393.     if (curr_msg>num_msgs-1)
  394.         curr_msg=num_msgs-1;
  395.  
  396.     if (curr_msg != -1) {
  397.         while ((headers[curr_msg].flags & DELETED) && (curr_msg<num_msgs-1))
  398.             curr_msg++;
  399.         if (headers[curr_msg].flags & DELETED)
  400.             while ((headers[curr_msg].flags & DELETED) && (curr_msg>0))
  401.                 curr_msg--;
  402.     }
  403.  
  404.     DisplayMsg();
  405. }
  406.  
  407. void PreviousMessage(void)
  408. {
  409.     curr_msg--;
  410.     if (curr_msg<0)
  411.         curr_msg=0;
  412.     if (num_msgs==0) {
  413.         curr_msg=-1;
  414.         return;
  415.     }
  416.  
  417.     while ((headers[curr_msg].flags & DELETED) && (curr_msg>0))
  418.         curr_msg--;
  419.     if (headers[curr_msg].flags & DELETED)
  420.         while ((headers[curr_msg].flags & DELETED) && (curr_msg<num_msgs-1))
  421.             curr_msg++;
  422.  
  423.     DisplayMsg();
  424. }
  425.  
  426. void NextSubjMessage(void)
  427. {
  428.     char sujet[100];
  429.     int  c;
  430.  
  431.     strcpy (sujet, strip_re(headers[curr_msg].topic));
  432.     c=curr_msg+1;
  433.  
  434.     while ((c<num_msgs) &&
  435.           !((!(headers[c].flags & DELETED)) && !stricmp (sujet, strip_re(headers[c].topic))))
  436.         c++;
  437.  
  438.     if (c<num_msgs)
  439.         curr_msg=c;
  440.     DisplayMsg();
  441. }
  442.  
  443. void PreviousSubjMessage(void)
  444. {
  445.     char sujet[100];
  446.     int  c;
  447.  
  448.     strcpy (sujet, strip_re(headers[curr_msg].topic));
  449.     c=curr_msg-1;
  450.     
  451.     while ((c>0) &&
  452.           !((!(headers[c].flags & DELETED)) && !stricmp (sujet, strip_re(headers[c].topic))))
  453.         c--;
  454.  
  455.     if (c>0)
  456.         curr_msg=c;
  457.     DisplayMsg();
  458. }
  459.  
  460. void GotoMessageCB(Widget w, long data, XmSelectionBoxCallbackStruct *cbs)
  461. {
  462.     int i;
  463.     char *value;
  464.  
  465.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  466.     i=atoi(value);
  467.     XtFree (value);
  468.     if ((i>0) && (i<=num_msgs))
  469.         curr_msg=i-1;
  470.     XtDestroyWidget (w);
  471.     DisplayMsg();
  472. }
  473.  
  474. void GotoMessage(void)
  475. {
  476.     Widget Popup;
  477.     XmString tmp;
  478.     Arg args[2];
  479.  
  480.     tmp=XmStringCreateSimple ("Goto message number...");
  481.     XtSetArg (args[0], XmNselectionLabelString, tmp);
  482.     XtSetArg (args[1], XmNautoUnmanage, False);
  483.     Popup=XmCreatePromptDialog (RowCol, "GotoMessage", args, 2);
  484.     XmStringFree (tmp);
  485.     
  486.     XtAddCallback (Popup, XmNokCallback, GotoMessageCB, NULL);
  487.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  488.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  489.     XtManageChild (Popup);
  490.     Focus (XmSelectionBoxGetChild(Popup, XmDIALOG_TEXT));
  491.     XtPopup (XtParent(Popup), XtGrabNone);
  492. }
  493.  
  494. void OpenArea(int numero)
  495. {
  496.     FILE    *head;
  497.     char    tmp[FILENAME_MAX];
  498.  
  499.     if (curr_area!=-1)
  500.         areas[curr_area].lastread=curr_msg;
  501.     curr_area=numero;
  502.  
  503.     sprintf (tmp, "%s.HDR", areas[numero].area_file);
  504.     head=fopen (tmp, "r");
  505.     if (head == NULL) {
  506.         num_msgs=0;
  507.         curr_msg=-1;
  508.         return;
  509.     }
  510.     fseek (head, 0, SEEK_END);
  511.     num_msgs=ftell (head) / sizeof (struct Hdr);
  512.     
  513.     if (headers != NULL)
  514.         free (headers);
  515.     headers=malloc(ftell(head));
  516.     fseek (head, 0, SEEK_SET);
  517.     fread (headers, sizeof (struct Hdr), num_msgs, head);
  518.     fclose (head);
  519.  
  520.     sprintf (tmp, "%s.MSG", areas[numero].area_file);
  521.     if (texts!=NULL)
  522.         fclose (texts);
  523.     texts=fopen (tmp, "r+");
  524.  
  525.     curr_msg=areas[numero].lastread;
  526.     if (curr_msg>num_msgs-1)
  527.         curr_msg=num_msgs-1;
  528.     if (curr_msg != -1) {
  529.         while ((headers[curr_msg].flags & DELETED) && (curr_msg<num_msgs-1))
  530.             curr_msg++;
  531.         while ((headers[curr_msg].flags & DELETED) && (curr_msg>0))
  532.             curr_msg--;
  533.     }
  534.     DisplayMsg();
  535. }
  536.  
  537. void NextArea (void)
  538. {
  539.     int i=curr_area+1;
  540.     if (i >= num_areas)
  541.         i=0;
  542.     OpenArea (i);
  543. }
  544.  
  545. void ChangeAreaCB (Widget w, long data, XmSelectionBoxCallbackStruct *cbs)
  546. {
  547.     char *name;
  548.     int i, j;
  549.  
  550.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &name);
  551.     j=curr_area;
  552.     for (i=0; i<num_areas; i++)
  553.         if (!strcmp(name, areas[i].area_name)) {
  554.             j=i;
  555.             break;
  556.         }
  557.     
  558.     XtFree (name);
  559.     XtDestroyWidget (w);
  560.     OpenArea(j);
  561. }
  562.  
  563. void ChangeArea (void)
  564. {
  565.     Widget Popup;
  566.     XmString *list;
  567.     char ligne[100];
  568.     int i;
  569.  
  570.     list = (XmString *) XtMalloc(num_areas*sizeof(XmString));
  571.     for (i=0; i<num_areas; i++) {
  572.         strcpy (ligne, areas[i].area_name);
  573.         list[i]=XmStringCreateSimple (ligne);
  574.     }
  575.     Popup=XmCreateSelectionDialog (RowCol, "ChangeArea", NULL, 0);
  576.     XtVaSetValues (Popup, Str (XmNlistLabelString, "Select area..."),
  577.                           XmNlistItems, list,
  578.                           XmNlistItemCount, num_areas,
  579.                           XmNmustMatch, True,
  580.                           NULL);
  581.     XtVaSetValues (XmSelectionBoxGetChild(Popup, XmDIALOG_LIST), XmNvisibleItemCount, 12, NULL);
  582.  
  583.     while (--i >= 0)
  584.         XmStringFree (list[i]);
  585.     XtFree (list);
  586.     XtAddCallback (Popup, XmNokCallback, ChangeAreaCB, NULL);
  587.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  588.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  589.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_APPLY_BUTTON));
  590.     XtManageChild (Popup);
  591.     XtPopup (XtParent(Popup), XtGrabNone);
  592. }
  593.  
  594. void ListMessageCB (Widget w, long data, XmSelectionBoxCallbackStruct *cbs)
  595. {
  596.     int i;
  597.     char *value;
  598.  
  599. #if 0
  600.     problem with different fonts!!
  601.     XmStringContext   context;
  602.     XmStringDirection direction;
  603.     XmStringCharSet   charset;
  604.     Boolean              separator;
  605.  
  606.     i=XmStringInitContext (&context, cbs->value);
  607.     i=XmStringGetNextSegment (context, &value, &charset, &direction, &separator);
  608.     i=XmStringGetNextSegment (context, &value, &charset, &direction, &separator);
  609.     XmStringFreeContext (context);
  610. #endif
  611.  
  612.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  613.     i=atoi(value+2);
  614.     XtFree (value);
  615.  
  616.     if ((i>0) && (i<=num_msgs))
  617.         curr_msg=i-1;
  618.  
  619.     XtDestroyWidget (w);
  620.     DisplayMsg();
  621. }
  622.  
  623. void ListMessage (void)
  624. {
  625.     Widget Popup;
  626.     XmString *list;
  627.     char ligne[100], sens;
  628.     int i, num;            /* num=nombre de message dans la liste */
  629.     int curr_msg_list;    /* index du message courant dans la liste */
  630.  
  631.     list = malloc(num_msgs*sizeof(XmString));
  632.     num=0;
  633.     for (i=0; i<num_msgs; i++) {
  634.         if (i==curr_msg)
  635.             curr_msg_list=num;
  636.         if (!(headers[i].flags & DELETED)) {
  637.             sens=' ';
  638.             if (!stricmp (sysop, headers[i].from))
  639.                 sens='<';
  640.             else if (!stricmp (sysop, headers[i].to))
  641.                 sens='>';
  642.             if (i==curr_msg)
  643.                 sens='=';
  644.             sprintf (ligne, "%c %3d  %-20.20s %-20.20s %-40.40s", sens, i+1, headers[i].from, headers[i].to, headers[i].topic);
  645.             list[num++]=XmStringCreateSimple (ligne/*, i==curr_msg? "char2":"char1" problems with later recognition!!!*/);
  646.         }
  647.     }
  648.     Popup=XmCreateSelectionDialog (RowCol, "SelectMessage", NULL, 0);
  649.     XtVaSetValues (Popup, Str (XmNlistLabelString, "Select message..."),
  650.                           XmNlistItems, list,
  651.                           XmNlistItemCount, num,
  652.                           XmNmustMatch, True,
  653.                           NULL);
  654.     XtVaSetValues (XmSelectionBoxGetChild(Popup, XmDIALOG_LIST), XmNvisibleItemCount, 25, NULL);
  655.  
  656.     while (--num >= 0)
  657.         XmStringFree (list[num]);
  658.     free (list);
  659.     XtAddCallback (Popup, XmNokCallback, ListMessageCB, NULL);
  660.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  661.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  662.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_APPLY_BUTTON));
  663.     XtManageChild (Popup);
  664.     MakePosVisible (XmSelectionBoxGetChild(Popup, XmDIALOG_LIST), curr_msg_list+1);
  665.     XtPopup (XtParent(Popup), XtGrabNone);
  666. }
  667.  
  668. int *setflags;
  669. char topic_str[80], to_str[35];
  670. Widget TopicWid, SendWid;
  671.  
  672. /* fermeture du dialogue principal -> mets le flag a un */
  673. void EditCB (Widget w, int *done, XmSelectionBoxCallbackStruct *cbs)
  674. {
  675.     char *value;
  676.     
  677.     switch (cbs->reason) {
  678.         case XmCR_OK:
  679.             *done=1;
  680.             XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  681.             strcpy (to_str, value);
  682.             XtFree (value);
  683.             break;
  684.         case XmCR_CANCEL:
  685.             *done=0;
  686.             break;
  687.     }
  688. }
  689.  
  690. /* fermeture du selecteur de fichier pour With File */
  691. void WFileCancelCB (Widget w, int *done, XmFileSelectionBoxCallbackStruct *cbs)
  692. {
  693.     XtDestroyWidget (w);
  694.     *done=0;
  695. }
  696.  
  697. void WFileCB (Widget w, int *done, XmFileSelectionBoxCallbackStruct *cbs)
  698. {
  699.     char *value;
  700.  
  701.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  702.     strcpy (topic_str, value);
  703.     XtFree (value);
  704.     XmTextFieldSetString (TopicWid, topic_str);
  705.     XtDestroyWidget (w);
  706.     *done=1;
  707. }
  708.  
  709. /* selection de With File -> affiche un selecteur de fichier */
  710. int WFileSelect (void)
  711. {
  712.     Widget FileSB;
  713.     Arg args[2];
  714.     int done;
  715.     
  716.     XtSetArg (args[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
  717.     FileSB=XmCreateFileSelectionDialog (RowCol, "WFileSB", args, 1);
  718.     XtAddCallback (FileSB, XmNcancelCallback, WFileCancelCB, &done);
  719.     XtAddCallback (FileSB, XmNokCallback, WFileCB, &done);
  720.     XtManageChild (FileSB);
  721.     XtSetSensitive (XmFileSelectionBoxGetChild (FileSB, XmDIALOG_HELP_BUTTON), False);
  722.     XtPopup (XtParent(FileSB), XtGrabNone);
  723.  
  724.     /* attente */
  725.     done=-1;
  726.     while (done==-1) {
  727.         XtAppProcessEvent (App, XtIMAll);
  728.         XSync (XtDisplay (SendWid), 0);
  729.     }
  730.     return done;
  731. }
  732.     
  733. Widget Toggle;
  734. /* changement d'etat d'un bouton */
  735. void ToggleCB (Widget w, int mask, XmToggleButtonCallbackStruct *cbs)
  736. {
  737.     if (cbs->set)
  738.         *setflags |= mask;
  739.     else
  740.         *setflags &= ~mask;
  741. }
  742.  
  743. /* creation des boutons */
  744. void Buttons (char *nom, int mask)
  745. {
  746.     Widget w;
  747.  
  748.     w=XtVaCreateManagedWidget (nom, xmToggleButtonGadgetClass, Toggle, NULL);
  749.     if (*setflags & mask)
  750.         XmToggleButtonSetState (w, True, False);
  751.     XtAddCallback (w, XmNvalueChangedCallback, ToggleCB, mask);
  752. }
  753.  
  754. int EditHeader (int netmail, char **to, char **topic, int *dzone, int *dnet, int *dnode, int *dpoint, int *flags)
  755. {
  756.     Widget w;
  757.     XmString tmp;
  758.     Arg args[4];
  759.     int done;
  760.     char *node, *ptr;
  761.     
  762.     tmp=XmStringCreateSimple ("Send message to");
  763.     XtSetArg (args[0], XmNselectionLabelString, tmp);
  764.     XtSetArg (args[1], XmNautoUnmanage, False);
  765.     XtSetArg (args[2], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
  766.     SendWid=XmCreatePromptDialog (RowCol, "SendMessage", args, 3);
  767.     XmStringFree (tmp);
  768.  
  769.     /* creation widget flags */
  770.     setflags=flags;
  771.     strcpy (topic_str, *topic);
  772.     strcpy (to_str, *to);
  773.  
  774.     w=XtVaCreateManagedWidget ("Frame", xmFrameWidgetClass, SendWid, XmNshadowType, XmSHADOW_OUT, NULL);
  775.     w=XtVaCreateManagedWidget ("Frame1", xmRowColumnWidgetClass, w, NULL);
  776.     Toggle=XtVaCreateWidget ("Flags", xmRowColumnWidgetClass, w,
  777.             XmNpacking, XmPACK_COLUMN,
  778.             XmNorientation, XmVERTICAL,
  779.             XmNnumColumns, 7,
  780.             NULL);
  781.  
  782.     if (netmail) {
  783.         Buttons ("Private", PRIVATE);
  784.         Buttons ("Crash", CRASH);
  785.         Buttons ("With File", FILEATCH);
  786.         Buttons ("Kill sent", KILLSEND);
  787.         Buttons ("Hold", MSGHOLD);
  788.         Buttons ("Direct", DIRECT);
  789.         Buttons ("CarbonCopy", CARBONCOPY);
  790.         if (*dzone+*dnet+*dnode+*dpoint != 0)
  791.             sprintf (to_str, "%s @ %d:%d/%d.%d", *to, *dzone, *dnet, *dnode, *dpoint);
  792.     }
  793.  
  794.     /* creation widget topic */
  795.     w = XtVaCreateManagedWidget ("Frame2", xmRowColumnWidgetClass, w, XmNnumColumns, 2, NULL);
  796.     XtVaCreateManagedWidget ("Subject ", xmLabelGadgetClass, w, NULL);
  797.     TopicWid = XtVaCreateManagedWidget ("Topic", xmTextFieldWidgetClass, w, NULL);
  798.     XmTextFieldSetString(TopicWid, topic_str);
  799.  
  800.     XtVaSetValues (SendWid, Str (XmNtextString, to_str), NULL);
  801.     
  802.     XtAddCallback (SendWid, XmNokCallback, EditCB, &done);
  803.     XtAddCallback (SendWid, XmNcancelCallback, EditCB, &done);
  804.     XtUnmanageChild (XmSelectionBoxGetChild(SendWid, XmDIALOG_HELP_BUTTON));
  805.     XtManageChild (Toggle);
  806.     XtManageChild (SendWid);
  807.     Focus (XmSelectionBoxGetChild(SendWid, XmDIALOG_TEXT));
  808.     XtPopup (XtParent(SendWid), XtGrabNone);
  809.  
  810.     done=-1;
  811.     while (done==-1) {
  812.         XtAppProcessEvent (App, XtIMAll);
  813.         XSync (XtDisplay (SendWid), 0);
  814.     }
  815.  
  816.     if (done) {
  817.         /* get Topic */
  818.         if (FILEATCH & *setflags)
  819.             done=WFileSelect();
  820.         if (done) {
  821.             ptr=XmTextFieldGetString (TopicWid);
  822.             strcpy (topic_str, ptr);
  823.             XtFree (ptr);
  824.             *topic=topic_str;
  825.             *to=to_str;
  826.             if (netmail)
  827.                 ParseAdr (to_str, dzone, dnet, dnode, dpoint);
  828.         }
  829.     }
  830.  
  831.     XtUnmanageChild (SendWid);
  832.     XSync (XtDisplay(SendWid), 0);
  833.     XmUpdateDisplay (SendWid);
  834.  
  835.     return done;
  836. }
  837.  
  838. void WriteMsg (int numero, char *to, char *topic, int dzone, int dnet, int dnode, int dpoint, int flags)
  839. {
  840.     FILE    *msg;
  841.     char    tmp[100];
  842.     struct    Hdr head;
  843.     int        len, i;
  844.     char    c;
  845.  
  846.     msg=fopen (temp1, "r");
  847.     if (msg==NULL)
  848.         return;
  849.     if (numero != curr_area) {
  850.         if (texts != NULL)
  851.             fclose (texts);
  852.         sprintf (tmp, "%s.MSG", areas[numero].area_file);
  853.         texts=fopen (tmp, "r+");
  854.     }
  855.  
  856.     fseek (texts, 0, SEEK_END);
  857.  
  858.     /* construction header */
  859.     head.Mstart=ftell (texts);
  860.     head.create=time(NULL);
  861.     head.up=head.parent=head.reads=head.cost=0;
  862.     head.flags=flags|MSGLOCAL;
  863.     head.Ozone=ourzone; head.Onet=ournet; head.Onode=ournode; head.Opoint=ourpoint;
  864.     head.Dzone=dzone; head.Dnet=dnet; head.Dnode=dnode; head.Dpoint=dpoint;
  865.     for (i=0; i<=7; i++) head.mailer[i]=0;
  866.     strncpy (head.from, sysop, 36); head.from[35]=0;
  867.     strncpy (head.to, to, 36); head.to[35]=0;
  868.     strncpy (head.topic, topic, 72); head.topic[71]=0;
  869.     strftime(head.time,20,"%d %b %y  %H:%M:%S",localtime(&head.create));
  870.     len=0;
  871.  
  872.     /* pid */
  873.     sprintf (tmp, "\01PID: Bed %s\n", BedVersion);
  874.     fputs (tmp, texts); len += strlen(tmp);
  875.  
  876.     /* msgid */
  877.     if(ourpoint==0)
  878.         sprintf(tmp,"\01MSGID: %d:%d/%d %8.8lx\n", ourzone, ournet, ournode, head.create);
  879.     else
  880.         sprintf(tmp,"\01MSGID: %d:%d/%d.%d %8.8lx\n", ourzone, ournet, ournode, ourpoint, head.create);
  881.     fputs (tmp, texts); len += strlen(tmp);
  882.  
  883.     /* reply */
  884.     if(replyid[0]) {
  885.         sprintf(tmp, "\01REPLY:%s\n", replyid);
  886.         fputs (tmp, texts); len += strlen(tmp);
  887.     }
  888.     
  889.     /* texte */
  890.     while (!feof(msg)) {
  891.         c=getc(msg);
  892.         if (c==EOF) break;
  893.         putc (c, texts);
  894.         len++;
  895.     }
  896.     fclose (msg);    
  897.  
  898.     /* ecriture header */
  899.     head.size= (ushort) len;
  900.     sprintf (tmp, "%s.HDR", areas[numero].area_file);
  901.     msg=fopen (tmp, "a");
  902.     fwrite (&head, sizeof (struct Hdr), 1, msg);
  903.     fclose (msg);
  904.  
  905.     if (numero != curr_area) {
  906.         fclose (texts);
  907.         sprintf (tmp, "%s.MSG", areas[curr_area].area_file);
  908.         texts=fopen (tmp, "r+");
  909.     }
  910. }
  911.  
  912. char carbon_file[80];
  913. void CarbonCB (Widget w, int *done, XmFileSelectionBoxCallbackStruct *cbs)
  914. {
  915.     char *value;
  916.  
  917.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  918.     strcpy (carbon_file, value);
  919.     XtFree (value);
  920.     XtDestroyWidget (w);
  921.     *done=1;
  922. }
  923.  
  924.  
  925. void PostMsg (int numero, char *to, char *topic, int dzone, int dnet, int dnode, int dpoint, int flags)
  926. {
  927.     FILE    *msg;
  928.     FILE    *carbon, *copy;
  929.     char    ligne[100], carb_to[36], c;
  930.     int        carb_zone, carb_net, carb_node, carb_point;
  931.     Arg        args[2];
  932.     Widget    FileSB;
  933.     int        done;
  934.     
  935.     /* edit from/to etc */
  936.     if (!EditHeader (!numero, &to, &topic, &dzone, &dnet, &dnode, &dpoint, &flags))
  937.         return;
  938.     
  939.     /* starts text editor */
  940.     sprintf (ligne, "%s %s", edit_cmd, temp1);
  941.     system (ligne);
  942.     msg=fopen (temp1, "r");
  943.     if (msg==NULL)
  944.         return;
  945.     fclose (msg);
  946.  
  947.     if (CARBONCOPY & flags) {
  948.         flags &= ~CARBONCOPY;
  949.         /* ask for filename */
  950.         XtSetArg (args[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
  951.         FileSB=XmCreateFileSelectionDialog (RowCol, "CarbonSB", args, 1);
  952.         XtAddCallback (FileSB, XmNcancelCallback, WFileCancelCB, &done);
  953.         XtAddCallback (FileSB, XmNokCallback, CarbonCB, &done);
  954.         XtManageChild (FileSB);
  955.         XtSetSensitive (XmFileSelectionBoxGetChild (FileSB, XmDIALOG_HELP_BUTTON), False);
  956.         XtPopup (XtParent(FileSB), XtGrabNone);
  957.  
  958.         /* attente */
  959.         done=-1;
  960.         while (done==-1) {
  961.             XtAppProcessEvent (App, XtIMAll);
  962.             XSync (XtDisplay (SendWid), 0);
  963.         }
  964.         if (!done)
  965.             exit;
  966.         carbon = fopen (carbon_file, "r");
  967.         if (carbon==NULL)
  968.             exit;
  969.         copy = fopen (temp2, "w");
  970.         msg=fopen(temp1, "r");
  971.         while (!feof(msg)) {
  972.             c=getc(msg);
  973.             if (c==EOF) break;
  974.             putc (c, copy);
  975.         }
  976.         /* add CC information */
  977.         fprintf (copy, "\nOriginal to: %s (%d:%d/%d.%d)\n", to, dzone, dnet, dnode, dpoint);
  978.         while (!feof(carbon)) {
  979.             if (fgets (ligne, 100, carbon)) {
  980.                 ParseAdr (ligne, &carb_zone, &carb_net, &carb_node, &carb_point);
  981.                 strcpy (carb_to, ligne);
  982.                 fprintf (copy, "CC: %s (%d:%d/%d.%d)\n", carb_to, carb_zone, carb_net, carb_node, carb_point);
  983.             }
  984.         }
  985.         putc ('\n', copy);
  986.  
  987.         fclose (msg);
  988.         fclose (copy);
  989.         rename (temp2, temp1);
  990.         WriteMsg (numero, to, topic, dzone, dnet, dnode, dpoint, flags);
  991.         rewind (carbon);
  992.         while (!feof(carbon)) {
  993.             if (fgets (ligne, 100, carbon)) {
  994.                 ParseAdr (ligne, &carb_zone, &carb_net, &carb_node, &carb_point);
  995.                 strcpy (carb_to, ligne);
  996.                 WriteMsg (numero, carb_to, topic, carb_zone, carb_net, carb_node, carb_point, flags | KILLSEND);
  997.             }
  998.         }
  999.         fclose (carbon);
  1000.     } else
  1001.         WriteMsg (numero, to, topic, dzone, dnet, dnode, dpoint, flags);
  1002.     if (numero==curr_area)
  1003.         OpenArea (curr_area);
  1004. }
  1005.  
  1006. void Wakeup(void)
  1007. {
  1008.     FILE *led;
  1009.     char ledfile[80], *mailer;
  1010.     int  area;
  1011.  
  1012.     if (curr_area!=-1)
  1013.         areas[curr_area].lastread=curr_msg;
  1014.  
  1015.     mailer=getenv("MAILER");
  1016.     if (mailer) sprintf (ledfile, "%s/led.new", mailer); else strcpy (ledfile, "led.new");
  1017.     led=fopen(ledfile, "w");
  1018.        for (area=0; area<num_areas; area++)
  1019.         fprintf (led, "%-16s %-4d %d\n", areas[area].area_name,
  1020.                     areas[area].lastread==-1? 0:areas[area].lastread, areas[area].flags);
  1021.     fclose (led);
  1022.     exit (0);
  1023. }
  1024.  
  1025. void quote(FILE *msg)
  1026. {
  1027.     char *buffer, *scan, *c, sys2;
  1028.     int c1 = 0;        /* counter since last CR */
  1029.     int c2 = 0;       /* counter since last SPACE */
  1030.     unsigned char *t, *s;
  1031.  
  1032.     if (echopoint)
  1033.          fprintf (msg, "In a message of <%s>, %s (%d:%d/%d.%d) writes :\n\n", headers[curr_msg].time, headers[curr_msg].from, echozone, echonet, echonode, echopoint);
  1034.     else fprintf (msg, "In a message of <%s>, %s (%d:%d/%d) writes :\n\n", headers[curr_msg].time, headers[curr_msg].from, echozone, echonet, echonode);
  1035.  
  1036.     buffer=XtMalloc(headers[curr_msg].size+1);
  1037.     fseek (texts, headers[curr_msg].Mstart, SEEK_SET);
  1038.     fread (buffer, 1, headers[curr_msg].size+1, texts);
  1039.     buffer[headers[curr_msg].size]=0;
  1040.  
  1041.    /* mksoftcr */
  1042.    for (t=buffer; *t; t++)
  1043.    {
  1044.       c1++;
  1045.       c2++;
  1046.  
  1047.       *t = Pc2Iso (*t);
  1048.  
  1049.       if ((*t == '\n') || (*t == '\r'))
  1050.          {
  1051.          *t = '\n';
  1052.          c1 = 0;/* reset counters */
  1053.          c2 = 0;
  1054.          continue;
  1055.          }
  1056.       else
  1057.         {
  1058.         if ((*t == ' ') || (*t == '\t'))
  1059.            {
  1060.            s = t;
  1061.            c2 = 0;
  1062.            continue;
  1063.            }
  1064.         else
  1065.            {
  1066.            if (c1 > 78-7)
  1067.               {
  1068.               *s = '\n';
  1069.               c1 = c2;
  1070.               continue;
  1071.               }
  1072.         }
  1073.       }
  1074.    }
  1075.  
  1076.     c=strchr (headers[curr_msg].from, ' ');
  1077.     sys2=' ';
  1078.     if (c!=NULL)
  1079.         sys2=*(c+1);
  1080.     
  1081.     scan = buffer;
  1082.     do {
  1083.         c=strchr (scan, '\n');
  1084.         if (c==NULL)
  1085.             break;
  1086.         if (scan[0]!='\01') {
  1087.             *c=0;
  1088.             if ((strlen(scan)>=1) && (scan[1]=='>'))
  1089.                     fprintf (msg, " %c%c>%s\n", headers[curr_msg].from[0], sys2, scan+1);
  1090.             else if ((strlen(scan)>=5) && (scan[3]=='>'))
  1091.                     fprintf (msg, " %c%c>>%s\n", scan[1], scan[2], scan+5);
  1092.             else    fprintf (msg, " %c%c> %s\n", headers[curr_msg].from[0], sys2, scan);
  1093.         }
  1094.         scan=c+1;
  1095.     } while (1);
  1096.     XtFree (buffer);
  1097. }
  1098.  
  1099. void ReplyNetmail(void)
  1100. {
  1101.     FILE *msg;
  1102.     char topic[100];
  1103.  
  1104.     if ((curr_area==0) || (curr_msg==-1))
  1105.         return;
  1106.     msg=fopen(temp1, "w");
  1107.     fprintf (msg, "In area %s\n", areas[curr_area].area_name);
  1108.     quote (msg);
  1109.     fclose (msg);
  1110.  
  1111.     if (strnicmp (headers[curr_msg].topic, "Re: ", 4))
  1112.             sprintf (topic, "Re: %s", headers[curr_msg].topic);
  1113.     else    strcpy (topic, headers[curr_msg].topic);
  1114.  
  1115.     PostMsg (0, headers[curr_msg].from, topic, echozone, echonet, echonode, echopoint, PRIVATE);
  1116. }
  1117.  
  1118. void Reply(void)
  1119. {
  1120.     FILE *msg;
  1121.     char topic[100];
  1122.  
  1123.     if (curr_msg==-1)
  1124.         return;
  1125.  
  1126.     msg=fopen(temp1, "w");
  1127.     quote (msg);
  1128.     fclose (msg);
  1129.  
  1130.     if (strnicmp (headers[curr_msg].topic, "Re: ", 4))
  1131.             sprintf (topic, "Re: %s", headers[curr_msg].topic);
  1132.     else    strcpy (topic, headers[curr_msg].topic);
  1133.  
  1134.     if (curr_area==0) PostMsg (curr_area, headers[curr_msg].from, topic, headers[curr_msg].Ozone, headers[curr_msg].Onet, headers[curr_msg].Onode, headers[curr_msg].Opoint, PRIVATE);
  1135.     else              PostMsg (curr_area, headers[curr_msg].from, topic, echozone, echonet, echonode, echopoint, 0);
  1136. }
  1137.  
  1138. void SaveMessageCB (Widget w, long data, XmFileSelectionBoxCallbackStruct *cbs)
  1139. {
  1140.     char *buffer, *name;
  1141.     FILE *fichier;
  1142.  
  1143.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &name);
  1144.     fichier = fopen (name, "a");
  1145.  
  1146.     /* header */
  1147.     fprintf (fichier, "Area   %s  [%d/%d]\n", areas[curr_area].area_name, curr_msg+1, num_msgs);
  1148.     if (curr_area==0) {
  1149.         fprintf (fichier, "From:  %s (%d:%d/%d.%d)\n", headers[curr_msg].from, headers[curr_msg].Ozone, headers[curr_msg].Onet, headers[curr_msg].Onode, headers[curr_msg].Opoint);
  1150.         fprintf (fichier, "To:    %s (%d:%d/%d.%d)\n", headers[curr_msg].to, headers[curr_msg].Dzone, headers[curr_msg].Dnet, headers[curr_msg].Dnode, headers[curr_msg].Dpoint);
  1151.     } else {
  1152.         fprintf (fichier, "From:  %s\n", headers[curr_msg].from);
  1153.         fprintf (fichier, "To:    %s\n", headers[curr_msg].to);
  1154.     }
  1155.     fprintf (fichier, "Date:  %s\n", headers[curr_msg].time);
  1156.     fprintf (fichier, "Subj:  %s\n", headers[curr_msg].topic);
  1157.     fputs ("------\n\n", fichier);
  1158.     
  1159.     /* texte */
  1160.     buffer = XmTextGetString (TextWidget);
  1161.     fwrite (buffer, 1, strlen(buffer), fichier);
  1162.     XtFree (buffer);
  1163.     XtFree (name);
  1164.     fclose (fichier);
  1165.     XtDestroyWidget (w);
  1166. }
  1167.  
  1168. void SaveMessage (void)
  1169. {
  1170.     Widget Popup;
  1171.  
  1172.     if (curr_msg==-1)
  1173.         return;
  1174.  
  1175.     Popup=XmCreateFileSelectionDialog (RowCol, "FileSB", NULL, 0);
  1176.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  1177.     XtAddCallback (Popup, XmNokCallback, SaveMessageCB, NULL);
  1178.     XtManageChild (Popup);
  1179.     XtSetSensitive (XmFileSelectionBoxGetChild (Popup, XmDIALOG_HELP_BUTTON), False);
  1180.     XtPopup (XtParent(Popup), XtGrabNone);
  1181. }
  1182.  
  1183. void PrintMessage (void)
  1184. {
  1185.     FILE *fichier;
  1186.     char *buffer;
  1187.     
  1188.     if (curr_msg==-1)
  1189.         return;
  1190.  
  1191.     fichier = popen ("lpr ", "w");
  1192.  
  1193.     /* header */
  1194.     fprintf (fichier, "Area   %s  [%d/%d]\n", areas[curr_area].area_name, curr_msg+1, num_msgs);
  1195.     if (curr_area==0) {
  1196.         fprintf (fichier, "From:  %s (%d:%d/%d.%d)\n", headers[curr_msg].from, headers[curr_msg].Ozone, headers[curr_msg].Onet, headers[curr_msg].Onode, headers[curr_msg].Opoint);
  1197.         fprintf (fichier, "To:    %s (%d:%d/%d.%d)\n", headers[curr_msg].to, headers[curr_msg].Dzone, headers[curr_msg].Dnet, headers[curr_msg].Dnode, headers[curr_msg].Dpoint);
  1198.     } else {
  1199.         fprintf (fichier, "From:  %s\n", headers[curr_msg].from);
  1200.         fprintf (fichier, "To:    %s\n", headers[curr_msg].to);
  1201.     }
  1202.     fprintf (fichier, "Date:  %s\n", headers[curr_msg].time);
  1203.     fprintf (fichier, "Subj:  %s\n", headers[curr_msg].topic);
  1204.     fputs ("------\n\n", fichier);
  1205.     
  1206.     /* texte */
  1207.     buffer = XmTextGetString (TextWidget);
  1208.     fwrite (buffer, 1, strlen(buffer), fichier);
  1209.     XtFree (buffer);
  1210.     pclose (fichier);
  1211. }
  1212.  
  1213. char *name;
  1214. Widget NumToWidget;
  1215.  
  1216. void SaveSeveralMessageCB2 (Widget w, long data, XmSelectionBoxCallbackStruct *cbs)
  1217. {
  1218.     char *buffer, *endkludge, *value, *t;
  1219.     FILE *fichier;
  1220.     int from, to, i;
  1221.  
  1222.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  1223.     to=atoi(value)-1;
  1224.     XtFree (value);
  1225.     value=XmTextFieldGetString (NumToWidget);
  1226.     from=atoi(value)-1;
  1227.     XtFree (value);
  1228.     XtDestroyWidget (w);
  1229.     
  1230.     if (to<from)
  1231.         return;
  1232.  
  1233.     fichier = fopen (name, "a");
  1234.     XtFree (name);
  1235.  
  1236.     for (i=from; i<=to; i++)
  1237.       if ((i>=0) && (i<=num_msgs) && !(DELETED & headers[i].flags)) {
  1238.         /* header */
  1239.         fprintf (fichier, "Area   %s  [%d/%d]\n", areas[curr_area].area_name, i+1, num_msgs);
  1240.         if (curr_area==0) {
  1241.             fprintf (fichier, "From:  %s (%d:%d/%d.%d)\n", headers[i].from, headers[i].Ozone, headers[i].Onet, headers[i].Onode, headers[i].Opoint);
  1242.             fprintf (fichier, "To:    %s (%d:%d/%d.%d)\n", headers[i].to, headers[i].Dzone, headers[i].Dnet, headers[i].Dnode, headers[i].Dpoint);
  1243.         } else {
  1244.             fprintf (fichier, "From:  %s\n", headers[i].from);
  1245.             fprintf (fichier, "To:    %s\n", headers[i].to);
  1246.         }
  1247.         fprintf (fichier, "Date:  %s\n", headers[i].time);
  1248.         fprintf (fichier, "Subj:  %s\n", headers[i].topic);
  1249.         fputs ("------\n\n", fichier);
  1250.     
  1251.         /* texte */
  1252.         buffer=XtMalloc(headers[i].size+1);
  1253.         fseek (texts, headers[i].Mstart, SEEK_SET);
  1254.         fread (buffer, 1, headers[i].size+1, texts);
  1255.         buffer[headers[i].size]=0;
  1256.  
  1257.         /* zap les kludges du debut */
  1258.         endkludge=buffer;
  1259.         while (*endkludge=='\01')
  1260.             endkludge=strchr(endkludge, '\n')+1;
  1261.  
  1262.         /* zap les seen-by de la fin */
  1263.         t=strstr (endkludge, "\01SEEN-BY");
  1264.         if (t != NULL)
  1265.             *t = 0;
  1266.  
  1267.         /* zap les Via de la fin */
  1268.         t=strstr (endkludge, "\01Via");
  1269.         if (t != NULL)
  1270.             *t = 0;
  1271.  
  1272.         mksoftcr (endkludge);
  1273.         fwrite (endkludge, 1, strlen(endkludge), fichier);
  1274.         XtFree (buffer);
  1275.         if (i!=to)
  1276.             fprintf (fichier, "\n------------------------------------------------------------------------\n");
  1277.     }
  1278.     fclose (fichier);
  1279. }
  1280.  
  1281. void SaveSeveralMessageCB1 (Widget w, long data, XmFileSelectionBoxCallbackStruct *cbs)
  1282. {
  1283.     Widget Popup;
  1284.     XmString tmp;
  1285.     Arg args[3];
  1286.     
  1287.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &name);
  1288.     XtDestroyWidget (w);
  1289.     
  1290.     tmp=XmStringCreateSimple (" to ");
  1291.     XtSetArg (args[0], XmNselectionLabelString, tmp);
  1292.     XtSetArg (args[1], XmNautoUnmanage, False);
  1293.     XtSetArg (args[2], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
  1294.     Popup=XmCreatePromptDialog (RowCol, "SelectMessages", args, 3);
  1295.     XmStringFree (tmp);
  1296.  
  1297.     w=XtVaCreateManagedWidget ("", xmRowColumnWidgetClass, Popup, NULL);
  1298.     XtVaCreateManagedWidget ("Save message from ", xmLabelGadgetClass, w, NULL);
  1299.     NumToWidget = XtVaCreateManagedWidget ("SaveTo", xmTextFieldWidgetClass, w, NULL);
  1300.  
  1301.     XtAddCallback (Popup, XmNokCallback, SaveSeveralMessageCB2, NULL);
  1302.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  1303.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  1304.     XtManageChild (Popup);
  1305.     Focus (NumToWidget);
  1306.     XtPopup (XtParent(Popup), XtGrabNone);
  1307. }
  1308.  
  1309. void SaveSeveralMessage (void)
  1310. {
  1311.     Widget Popup;
  1312.  
  1313.     if (curr_msg==-1)
  1314.         return;
  1315.  
  1316.     Popup=XmCreateFileSelectionDialog (RowCol, "Save messages", NULL, 0);
  1317.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  1318.     XtAddCallback (Popup, XmNokCallback, SaveSeveralMessageCB1, NULL);
  1319.     XtManageChild (Popup);
  1320.     XtSetSensitive (XmFileSelectionBoxGetChild (Popup, XmDIALOG_HELP_BUTTON), False);
  1321.     XtPopup (XtParent(Popup), XtGrabNone);
  1322. }
  1323.  
  1324. void EnterMessage (void)
  1325. {
  1326.     unlink (temp1);
  1327.     replyid[0]=0;
  1328.     PostMsg (curr_area, !curr_area? "":"All", "", 0, 0, 0, 0, !curr_area? PRIVATE:0);
  1329. }
  1330.  
  1331. void DeleteMessage (void)
  1332. {
  1333.     FILE *msg;
  1334.     char tmp[FILENAME_MAX];
  1335.     
  1336.     if (curr_msg==-1)
  1337.         return;
  1338.  
  1339.     headers[curr_msg].flags |= DELETED;
  1340.     sprintf (tmp, "%s.HDR", areas[curr_area].area_file);
  1341.     msg=fopen (tmp, "r+");
  1342.     fseek (msg, curr_msg*sizeof (struct Hdr), SEEK_SET);
  1343.     fwrite (&headers[curr_msg], sizeof (struct Hdr), 1, msg);
  1344.     fclose (msg);
  1345.     OpenArea (curr_area);
  1346. }
  1347.  
  1348. #define DeleteFlag   1
  1349. #define UndeleteFlag 0
  1350.  
  1351. void DeleteSeveralCB(Widget w, int flag, XmSelectionBoxCallbackStruct *cbs)
  1352. {
  1353.     int  i, from, to;
  1354.     char *value;
  1355.     FILE *msg;
  1356.     char tmp[100];
  1357.  
  1358.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  1359.     to=atoi(value)-1;
  1360.     XtFree (value);
  1361.     value=XmTextFieldGetString (NumToWidget);
  1362.     from=atoi(value)-1;
  1363.     XtFree (value);
  1364.  
  1365.     if (to == -1)
  1366.         to=from;
  1367.     if (from < 0)
  1368.         from=0;
  1369.     if (to > num_msgs)
  1370.         to=num_msgs;
  1371.     if (to < from) {
  1372.         XtDestroyWidget (w);
  1373.         return;
  1374.     }
  1375.     
  1376.     sprintf (tmp, "%s.HDR", areas[curr_area].area_file);
  1377.     msg=fopen (tmp, "r+");
  1378.  
  1379.     for (i=from; i<=to; i++)
  1380.         if (flag) headers[i].flags |= DELETED;
  1381.             else  headers[i].flags &= ~(DELETED+KILLSEND);
  1382.  
  1383.     fseek (msg, from*sizeof (struct Hdr), SEEK_SET);
  1384.     fwrite (&headers[from], sizeof (struct Hdr), to-from+1, msg);
  1385.     fclose (msg);
  1386.     XtDestroyWidget (w);
  1387.     OpenArea (curr_area);
  1388. }
  1389.  
  1390. void DeleteSeveralMessage(Widget z, int flag)
  1391. {
  1392.     Widget Popup, w;
  1393.     XmString tmp;
  1394.     Arg args[2];
  1395.  
  1396.     if (curr_msg==-1)
  1397.         return;
  1398.  
  1399.     tmp=XmStringCreateSimple (" to ");
  1400.     XtSetArg (args[0], XmNselectionLabelString, tmp);
  1401.     XtSetArg (args[1], XmNautoUnmanage, False);
  1402.     Popup=XmCreatePromptDialog (RowCol, "SelectMessages", args, 2);
  1403.     XmStringFree (tmp);
  1404.  
  1405.     w=XtVaCreateManagedWidget ("", xmRowColumnWidgetClass, Popup, NULL);
  1406.     if (flag)
  1407.         XtVaCreateManagedWidget ("Delete messages from ", xmLabelGadgetClass, w, NULL);
  1408.     else
  1409.         XtVaCreateManagedWidget ("Undelete messages from ", xmLabelGadgetClass, w, NULL);
  1410.     NumToWidget = XtVaCreateManagedWidget ("DeleteTo", xmTextFieldWidgetClass, w, NULL);
  1411.  
  1412.     XtAddCallback (Popup, XmNokCallback, DeleteSeveralCB, flag);
  1413.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  1414.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  1415.     XtManageChild (Popup);
  1416.     Focus (NumToWidget);
  1417.     XtPopup (XtParent(Popup), XtGrabNone);
  1418. }
  1419.  
  1420. void ChangeMessage(void)
  1421. {
  1422.     FILE    *msg;
  1423.     char    tmp[100], *buffer;
  1424.     struct    Hdr head;
  1425.     int        len, i;
  1426.     char    c;
  1427.  
  1428.     if (curr_msg==-1)
  1429.         return;
  1430.     /* ca supprime les kludges du message (ou ca les modifient) */
  1431.     
  1432.     /* edition */
  1433.     remove (temp1);
  1434.     buffer = XmTextGetString (TextWidget);
  1435.     msg=fopen (temp1, "w");
  1436.     fwrite (buffer, 1, strlen(buffer), msg);
  1437.     XtFree (buffer);
  1438.     fclose (msg);    
  1439.     sprintf (tmp, "%s %s", edit_cmd, temp1);
  1440.     system (tmp);
  1441.  
  1442.     msg=fopen (temp1, "r");
  1443.     fseek (texts, 0, SEEK_END);
  1444.  
  1445.     /* construction header */
  1446.     head=headers[curr_msg];
  1447.     head.Mstart=ftell (texts);
  1448.     head.create=time(NULL);
  1449.     head.flags=(head.flags|MSGLOCAL) & (~SENT);
  1450.     head.mailer[7]=0;
  1451.     head.Ozone=ourzone; head.Onet=ournet; head.Onode=ournode; head.Opoint=ourpoint;
  1452.     strncpy (head.from, sysop, 36); head.from[35]=0;
  1453.     strftime(head.time,20,"%d %b %y  %H:%M:%S",localtime(&head.create));
  1454.     len=0;
  1455.  
  1456.     /* pid */
  1457.     sprintf (tmp, "\01PID: Bed %s\n", BedVersion);
  1458.     fputs (tmp, texts); len += strlen(tmp);
  1459.  
  1460.     /* msgid */
  1461.     if(ourpoint==0)
  1462.         sprintf(tmp,"\01MSGID: %d:%d/%d %8.8lx\n", ourzone, ournet, ournode, head.create);
  1463.     else
  1464.         sprintf(tmp,"\01MSGID: %d:%d/%d.%d %8.8lx\n", ourzone, ournet, ournode, ourpoint, head.create);
  1465.     fputs (tmp, texts); len += strlen(tmp);
  1466.  
  1467.     /* texte */
  1468.     while (!feof(msg)) {
  1469.         c=getc(msg);
  1470.         if (c==EOF) break;
  1471.         putc (c, texts);
  1472.         len++;
  1473.     }
  1474.     fclose (msg);    
  1475.  
  1476.     /* ecriture header */
  1477.     head.size= (ushort) len;
  1478.     sprintf (tmp, "%s.HDR", areas[curr_area].area_file);
  1479.     msg=fopen (tmp, "a");
  1480.     fwrite (&head, sizeof (struct Hdr), 1, msg);
  1481.     
  1482.     /* effacement de l'ancien message */
  1483.     headers[curr_msg].flags |= DELETED;
  1484.     fseek (msg, curr_msg*sizeof (struct Hdr), SEEK_SET);
  1485.     fwrite (&headers[curr_msg], sizeof (struct Hdr), 1, msg);
  1486.     fclose (msg);
  1487.     OpenArea (curr_area);
  1488. }
  1489.  
  1490. void ForwardCB(Widget w, long data, XmSelectionBoxCallbackStruct *cbs)
  1491. {
  1492.     char *value, *node, *buffer, to_str[35];
  1493.     int dzone, dnet, dnode, dpoint;
  1494.     FILE *msg, *orig;
  1495.     
  1496.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  1497.     strcpy (to_str, value);
  1498.     XtFree (value);
  1499.     
  1500.     ParseAdr (to_str, &dzone, &dnet, &dnode, &dpoint);
  1501.  
  1502.     msg=fopen(temp1, "w");
  1503.     if (curr_area==0) {
  1504.         fprintf (msg, "* Originally from: %s (%d:%d/%d.%d)\n",   headers[curr_msg].from, headers[curr_msg].Ozone, headers[curr_msg].Onet, headers[curr_msg].Onode, headers[curr_msg].Opoint);
  1505.         fprintf (msg, "* Originally to:   %s (%d:%d/%d.%d)\n\n", headers[curr_msg].to,   headers[curr_msg].Dzone, headers[curr_msg].Dnet, headers[curr_msg].Dnode, headers[curr_msg].Dpoint);
  1506.     } else {
  1507.         fprintf (msg, "* Originally in area %s\n", areas[curr_area].area_name);
  1508.         fprintf (msg, "* Originally from: %s\n", headers[curr_msg].from);
  1509.         fprintf (msg, "* Originally to:   %s\n\n", headers[curr_msg].to);
  1510.     }
  1511.     buffer = XmTextGetString (TextWidget);
  1512.     fwrite (buffer, 1, strlen(buffer), msg);
  1513.     XtFree (buffer);
  1514.     fclose (msg);    
  1515.  
  1516.     WriteMsg (0, to_str, headers[curr_msg].topic, dzone, dnet, dnode, dpoint, PRIVATE+KILLSEND);
  1517.     
  1518.     XtDestroyWidget (w);
  1519.     OpenArea(curr_area);
  1520. }
  1521.  
  1522. void Forward(void)
  1523. {
  1524.     Widget Popup;
  1525.     XmString tmp;
  1526.     Arg args[3];
  1527.  
  1528.     tmp=XmStringCreateSimple ("Forward message to...");
  1529.     XtSetArg (args[0], XmNselectionLabelString, tmp);
  1530.     XtSetArg (args[1], XmNautoUnmanage, False);
  1531.     XtSetArg (args[2], XmNtextColumns, 35);
  1532.     Popup=XmCreatePromptDialog (RowCol, "ForwardMessage", args, 3);
  1533.     XmStringFree (tmp);
  1534.     
  1535.     XtAddCallback (Popup, XmNokCallback, ForwardCB, NULL);
  1536.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  1537.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  1538.     XtManageChild (Popup);
  1539.     Focus (XmSelectionBoxGetChild(Popup, XmDIALOG_TEXT));
  1540.     XtPopup (XtParent(Popup), XtGrabNone);
  1541. }
  1542.  
  1543. void insensitive (char *a, char *b)
  1544. {
  1545.     while (*a) {
  1546.         if ((*b == '[') || (*b == ']') || (*b == '*') || (*b == '.') || (*b == '\\')) {
  1547.             *b++ = '\\';
  1548.             *b++ = *a;
  1549.         } else {
  1550.             *b++ = '[';
  1551.             *b++ = tolower (*a);
  1552.             *b++ = toupper (*a);
  1553.             *b++ = ']';
  1554.         }
  1555.         a++;
  1556.     }
  1557.     *b=0;
  1558. }
  1559.  
  1560. void SearchSame(Widget w, Widget data)
  1561. {
  1562.     int     num;
  1563.     char *buffer;
  1564.  
  1565.     num=curr_msg+1;
  1566.     while (num<num_msgs) {
  1567.       if (!(headers[num].flags & DELETED)) {
  1568.         buffer=XtMalloc(headers[num].size+1);
  1569.         fseek (texts, headers[num].Mstart, SEEK_SET);
  1570.         fread (buffer, 1, headers[num].size+1, texts);
  1571.         buffer[headers[num].size]=0;
  1572.         if (re_exec(headers[num].topic) || re_exec(headers[num].to) ||
  1573.             re_exec(headers[num].from) || re_exec(buffer)) {
  1574.             XtFree (buffer);
  1575.             curr_msg=num;
  1576.             num=0;        /* use as a found flag */
  1577.             break;
  1578.         }
  1579.         XtFree (buffer);
  1580.       }
  1581.       num++;
  1582.     }
  1583.     DisplayMsg();
  1584.     /* destroy "Search" box if exist and last string not found */
  1585.     if (data && num)
  1586.         XtDestroyWidget (data);
  1587. }
  1588.  
  1589. void SearchCB(Widget w, long data, XmSelectionBoxCallbackStruct *cbs)
  1590. {
  1591.     char *value;
  1592.     
  1593.     XmStringGetLtoR (cbs->value, XmSTRING_DEFAULT_CHARSET, &value);
  1594.     re_comp (value);
  1595.     XtFree (value);
  1596.     SearchSame (NULL, w);
  1597. }
  1598.  
  1599. void Search(void)
  1600. {
  1601.     Widget Popup;
  1602.     XmString tmp;
  1603.     Arg args[3];
  1604.  
  1605.     tmp=XmStringCreateSimple ("Search ...");
  1606.     XtSetArg (args[0], XmNselectionLabelString, tmp);
  1607.     XtSetArg (args[1], XmNautoUnmanage, False);
  1608.     XtSetArg (args[2], XmNtextColumns, 35);
  1609.     Popup=XmCreatePromptDialog (RowCol, "Search", args, 3);
  1610.     XmStringFree (tmp);
  1611.     
  1612.     XtAddCallback (Popup, XmNokCallback, SearchCB, NULL);
  1613.     XtAddCallback (Popup, XmNcancelCallback, XtDestroyWidget, NULL);
  1614.     XtUnmanageChild (XmSelectionBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  1615.     XtManageChild (Popup);
  1616.     Focus (XmSelectionBoxGetChild(Popup, XmDIALOG_TEXT));
  1617.     XtPopup (XtParent(Popup), XtGrabNone);
  1618. }
  1619.  
  1620.  
  1621. /* add the sender of the current message to the user's list */
  1622. /* does not check for duplicate entry ! */
  1623. void AddSender(void)
  1624. {
  1625.     FILE *ulist;
  1626.     char *p, ligne[50];
  1627.  
  1628.     p=getenv ("MAILER");
  1629.         if (p)
  1630.             sprintf (ligne, "%s/ulist.txt", p);
  1631.         else
  1632.             strcpy (ligne, "ulist.txt");
  1633.     ulist=fopen (ligne, "a");
  1634.     if (curr_area==0)
  1635.         fprintf (ulist, "%s\t%d:%d/%d.%d\n", headers[curr_msg].from, headers[curr_msg].Ozone, headers[curr_msg].Onet, headers[curr_msg].Onode, headers[curr_msg].Opoint);
  1636.     else
  1637.         fprintf (ulist, "%s\t%d:%d/%d.%d\n", headers[curr_msg].from, echozone, echonet, echonode, echopoint);
  1638.     fclose (ulist);
  1639. }
  1640.  
  1641.  
  1642. void AboutBed(void)
  1643. {
  1644.     Widget Popup;
  1645.     XmString tmp;
  1646.     Arg args[3];
  1647.     char str[200];
  1648.  
  1649.     sprintf (str, "   Bed v%s - Bermuda EDitor \n\n   (c) Vincent Pomey  1993\n", BedVersion);
  1650.     tmp=XmStringCreateLtoR (str, XmSTRING_DEFAULT_CHARSET);
  1651.     XtSetArg (args[0], XmNmessageString, tmp);
  1652.     XtSetArg (args[1], XmNautoUnmanage, False);
  1653.     Popup=XmCreateInformationDialog (RowCol, "About Bed", args, 2);
  1654.     XmStringFree (tmp);
  1655.     
  1656.     XtAddCallback (Popup, XmNokCallback, XtDestroyWidget, NULL);
  1657.     XtUnmanageChild (XmMessageBoxGetChild(Popup, XmDIALOG_HELP_BUTTON));
  1658.     XtUnmanageChild (XmMessageBoxGetChild(Popup, XmDIALOG_CANCEL_BUTTON));
  1659.     XtManageChild (Popup);
  1660.     XtPopup (XtParent(Popup), XtGrabNone);
  1661. }
  1662.  
  1663. MenuItem file_items[] = {
  1664.     { "Change Area...", &xmPushButtonGadgetClass, 'A', "Ctrl<Key>A", "^A", ChangeArea, NULL },
  1665.     { "Next Area",      &xmPushButtonGadgetClass, 'W', "Ctrl<Key>W", "^W", NextArea, NULL },
  1666.     { "Save current...",&xmPushButtonGadgetClass, 'S', "Ctrl<Key>S", "^S", SaveMessage, NULL },
  1667.     { "Save several...",&xmPushButtonGadgetClass,NULL, NULL,         NULL, SaveSeveralMessage, NULL },
  1668.     { "Print current...",&xmPushButtonGadgetClass, 'P', "Ctrl<Key>P", "^P", PrintMessage, NULL },
  1669.     { "",               &xmSeparatorGadgetClass, NULL, NULL, NULL, NULL, NULL },
  1670.     { "Quit",           &xmPushButtonGadgetClass, 'Q', "Ctrl<Key>Q", "^Q", Wakeup, NULL },
  1671.     NULL},
  1672.          message_items[] = {
  1673.     { "Next",           &xmPushButtonGadgetClass, NULL, "<Key>End",   "->", NextMessage, NULL },
  1674.     { "Previous",       &xmPushButtonGadgetClass, NULL, "<Key>Begin", "<-", PreviousMessage, NULL },
  1675.     { "Goto...",        &xmPushButtonGadgetClass, 'G',  "Ctrl<Key>G", "^G", GotoMessage, NULL },
  1676.     { "List...",        &xmPushButtonGadgetClass, 'L',  "Ctrl<Key>L", "^L", ListMessage, NULL },
  1677.     { "Next Subj",      &xmPushButtonGadgetClass, NULL, "Ctrl<Key>I", "^I",  NextSubjMessage, NULL },
  1678.     { "Previous Subj",  &xmPushButtonGadgetClass, NULL, "Ctrl<Key>U", "^U",  PreviousSubjMessage, NULL },
  1679.     
  1680.     { "",               &xmSeparatorGadgetClass,  NULL, NULL, NULL, NULL, NULL },
  1681.     { "Delete current", &xmPushButtonGadgetClass, 'D',  "Ctrl<Key>D", "^D", DeleteMessage, NULL },
  1682.     { "Delete several", &xmPushButtonGadgetClass, NULL, "Ctrl<Key>K", "^K", DeleteSeveralMessage, (XtPointer) DeleteFlag },
  1683.     { "Undelete",       &xmPushButtonGadgetClass, NULL,  NULL,        NULL, DeleteSeveralMessage, (XtPointer) UndeleteFlag },
  1684.     { "Change",         &xmPushButtonGadgetClass,  'C', "Ctrl<Key>C", "^C", ChangeMessage, NULL },
  1685.     NULL},
  1686.         edit_items[] = {
  1687.     { "Enter...",       &xmPushButtonGadgetClass, 'E',  "Ctrl<Key>E", "^E", EnterMessage, NULL },
  1688.     { "Reply",          &xmPushButtonGadgetClass, 'R',  "Ctrl<Key>R", "^R", Reply, NULL },
  1689.     { "Reply in Netmail", &xmPushButtonGadgetClass,'N', "Ctrl<Key>N", "^N", ReplyNetmail, NULL },
  1690.     { "Forward...",     &xmPushButtonGadgetClass, 'F',  "Ctrl<Key>F", "^F", Forward, NULL },
  1691.     NULL},
  1692.         misc_items[] = {
  1693.     { "Search...",      &xmPushButtonGadgetClass, NULL, NULL,         NULL, Search, NULL },
  1694.     { "Search same",    &xmPushButtonGadgetClass, NULL, NULL,         NULL, SearchSame, NULL },
  1695.     { "Add sender in ulist", &xmPushButtonGadgetClass, NULL, NULL,    NULL, AddSender, NULL },
  1696.     NULL},
  1697.         help_items[] = {
  1698.     { "About Bed",      &xmPushButtonGadgetClass, NULL, NULL,         NULL, AboutBed, NULL },
  1699.     NULL};
  1700.  
  1701. main(argc, argv)
  1702. int argc;
  1703. char *argv[];
  1704. {
  1705.     Widget            TopLevel, MainWindow, MenuBar, FilePullDown, MessagePullDown;
  1706.     Arg                args[5];
  1707.     Pixmap            pixmap;
  1708.     Screen            *screen;
  1709.     
  1710.     /* lecture fichiers de config */
  1711.     readconfig();
  1712.     readareas();
  1713.  
  1714.     strcpy (temp1, "/tmp/bedXXXXXX"); mktemp (temp1); fclose (fopen (temp1, "w"));
  1715.     strcpy (temp2, "/tmp/bedXXXXXX"); mktemp (temp2); fclose (fopen (temp1, "w"));
  1716.     
  1717.     /* initialisation Motif */
  1718.     TopLevel = XtVaAppInitialize(&App, "Bed", NULL, 0, &argc, argv, NULL, NULL);
  1719.     XtGetApplicationResources (TopLevel, &edit_cmd, ressources, XtNumber(ressources), NULL, 0);
  1720.     MainWindow = XtVaCreateManagedWidget("mainwin", xmMainWindowWidgetClass, TopLevel, NULL);
  1721.     pixmap = XCreateBitmapFromData (XtDisplay(TopLevel), XtScreen(TopLevel)->root, bed_bits, bed_width, bed_height);
  1722.     XtVaSetValues (TopLevel, XmNiconPixmap, pixmap, NULL);
  1723.     
  1724.     /* barre de menu */
  1725.     MenuBar = XmCreateMenuBar(MainWindow,"menubar", NULL, 0);
  1726.     BuildMenu (MenuBar, "File", 'F', file_items);
  1727.     BuildMenu (MenuBar, "Edit", 'E', edit_items);
  1728.     BuildMenu (MenuBar, "Message", 'M', message_items);
  1729.     BuildMenu (MenuBar, "Others", 'O', misc_items);
  1730.     XtVaSetValues (MenuBar, XmNmenuHelpWidget, BuildMenu (MenuBar, "Help", 'H', help_items), NULL);
  1731.     XtManageChild(MenuBar);
  1732.  
  1733.     /* text area */
  1734.     RowCol = XtVaCreateWidget ("WorkArea", xmRowColumnWidgetClass, MainWindow, XmNpacking, XmPACK_TIGHT, NULL);
  1735.     AreaWidget = XtVaCreateManagedWidget ("Area", xmLabelGadgetClass, RowCol, NULL);
  1736.     FromWidget = XtVaCreateManagedWidget ("From", xmLabelGadgetClass, RowCol, NULL);
  1737.     ToWidget = XtVaCreateManagedWidget ("To", xmLabelGadgetClass, RowCol, NULL);
  1738.     DateWidget = XtVaCreateManagedWidget ("Date", xmLabelGadgetClass, RowCol, NULL);
  1739.     SubjWidget = XtVaCreateManagedWidget ("Subj", xmLabelGadgetClass, RowCol, NULL);
  1740.  
  1741.     XtSetArg (args[0], XmNeditable, False);
  1742.     XtSetArg (args[1], XmNeditMode, XmMULTI_LINE_EDIT);
  1743.     XtSetArg (args[2], XmNcursorPositionVisible, False);
  1744.     TextWidget = XmCreateScrolledText (RowCol, "message", args, 3);
  1745.     XtManageChild (TextWidget);
  1746.     XtManageChild (RowCol);
  1747.     XmMainWindowSetAreas (MainWindow, MenuBar, NULL, NULL, NULL, RowCol);
  1748.  
  1749.     OpenArea (0);
  1750.     
  1751.     XtRealizeWidget(TopLevel);
  1752.     XtAppMainLoop(App);
  1753.  
  1754.     unlink (temp1);
  1755.     unlink (temp2);
  1756. }
  1757.